// 闭包的语法

fn main() {
    // 闭包的参数位于|之中 而闭包体是一个表达式
    // 形式1
    let plus_one = |x: i32| x + 1;
    assert_eq!(3, plus_one(2));

    // 形式2
    let plus_two = |_x: i32| {
        let mut result: i32 = _x;
        result += 1;
        result
    };

    assert_eq!(3, plus_two(2));
    println!("{}", plus_two(2));

    // 形式3
    let plus_three = |x: i32| -> i32 { x + 1 };
    assert_eq!(3, plus_three(2));

    // move 闭包

    // 闭包作为参数和返回值
    // Fn是一个trait,可以用它来限制泛型，所以是一个单态的
    fn call_with_one<F>(some_closure: F) -> i32
    where
        F: Fn(i32) -> i32,
    {
        some_closure(1)
    }
    //闭包固定在堆上分配，动态分发调用也可以（在栈上分配我们闭包的环境，并静态分发调用）
    let answer = call_with_one(|x| x + 2);
    println!("获取值{:?}", answer);

    fn call_with_one_v1(some_closure: &Fn(i32) -> i32) -> i32 {
        some_closure(1)
    }

    let answer_v1 = call_with_one_v1(&|x| x + 2);
    println!("获取值{:?}", answer_v1);

    // 函数指针和闭包
    // 函数指针（一个没有环境的闭包),可以传递函数指针给任何函数除了作为闭包参数

    // 返回闭包
    fn factory() -> Box<Fn(i32) -> i32> {
        let num = 5;
        Box::new(move |x| x + num)
    }

    let f = factory();
    
    let answer = f(1);
    assert_eq!(6, answer);

}
